library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
── Attaching packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.4 ✓ purrr 0.3.4
✓ tibble 3.1.2 ✓ dplyr 1.0.7
✓ tidyr 1.1.3 ✓ stringr 1.4.0
✓ readr 1.4.0 ✓ forcats 0.5.1
── Conflicts ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
library(MatrixGenerics)
Loading required package: matrixStats
Attaching package: ‘matrixStats’
The following object is masked from ‘package:dplyr’:
count
Attaching package: ‘MatrixGenerics’
The following objects are masked from ‘package:matrixStats’:
colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse, colCounts, colCummaxs, colCummins, colCumprods, colCumsums, colDiffs, colIQRDiffs, colIQRs,
colLogSumExps, colMadDiffs, colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats, colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads, colWeightedMeans, colWeightedMedians, colWeightedSds, colWeightedVars, rowAlls, rowAnyNAs, rowAnys,
rowAvgsPerColSet, rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods, rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps, rowMadDiffs, rowMads,
rowMaxs, rowMeans2, rowMedians, rowMins, rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks, rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs,
rowVars, rowWeightedMads, rowWeightedMeans, rowWeightedMedians, rowWeightedSds, rowWeightedVars
library(SingleCellExperiment)
Loading required package: SummarizedExperiment
Loading required package: GenomicRanges
Loading required package: stats4
Loading required package: BiocGenerics
Loading required package: parallel
Attaching package: ‘BiocGenerics’
The following objects are masked from ‘package:parallel’:
clusterApply, clusterApplyLB, clusterCall, clusterEvalQ, clusterExport, clusterMap, parApply, parCapply, parLapply, parLapplyLB, parRapply, parSapply, parSapplyLB
The following objects are masked from ‘package:dplyr’:
combine, intersect, setdiff, union
The following objects are masked from ‘package:stats’:
IQR, mad, sd, var, xtabs
The following objects are masked from ‘package:base’:
anyDuplicated, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find, get, grep, grepl, intersect,
is.unsorted, lapply, Map, mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank, rbind, Reduce, rownames, sapply, setdiff, sort,
table, tapply, union, unique, unsplit, which.max, which.min
Loading required package: S4Vectors
Attaching package: ‘S4Vectors’
The following objects are masked from ‘package:dplyr’:
first, rename
The following object is masked from ‘package:tidyr’:
expand
The following objects are masked from ‘package:base’:
expand.grid, I, unname
Loading required package: IRanges
Attaching package: ‘IRanges’
The following objects are masked from ‘package:dplyr’:
collapse, desc, slice
The following object is masked from ‘package:purrr’:
reduce
Loading required package: GenomeInfoDb
Loading required package: Biobase
Welcome to Bioconductor
Vignettes contain introductory material; view with 'browseVignettes()'. To cite Bioconductor, see 'citation("Biobase")', and for packages 'citation("pkgname")'.
Attaching package: ‘Biobase’
The following object is masked from ‘package:MatrixGenerics’:
rowMedians
The following objects are masked from ‘package:matrixStats’:
anyMissing, rowMedians
lseq <- function(from, to, length.out){
exp(seq(log(from), log(to), length.out = length.out))
}
theme_set(cowplot::theme_cowplot())
library(org.Hs.eg.db)
Loading required package: AnnotationDbi
Attaching package: ‘AnnotationDbi’
The following object is masked from ‘package:dplyr’:
select
human_cell_cycle_genes <- select(org.Hs.eg.db, keytype = "GOALL", keys = "GO:0007049", columns = "ENSEMBL")[, "ENSEMBL"]
Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
'select()' returned 1:many mapping between keys and columns
library(org.Mm.eg.db)
mouse_cell_cycle_genes <- select(org.Mm.eg.db, keytype = "GOALL", keys = "GO:0007049", columns = "ENSEMBL")[, "ENSEMBL"]
'select()' returned 1:many mapping between keys and columns
mu_sup <- lseq(1e-4, 1e6, length.out = 1001)
poisson_pred <- cross_df(list(mu = mu_sup, factor = 10^seq(-8, 8))) %>%
mutate(var = mu * factor)
gampoi_pred <- cross_df(list(mu = mu_sup, factor = 10^seq(-2, 2, by = 2))) %>%
mutate(var = mu + mu^2 * factor)
Prepare Data
Download data
# Work around for some bug in zellkonverter
# https://github.com/theislab/zellkonverter/issues/45
setAs("dgRMatrix", to = "dgCMatrix", function(from){
as(as(from, "CsparseMatrix"), "dgCMatrix")
})
if(! file.exists("../data/klein_2015.h5ad")){
download.file("https://data.caltech.edu/tindfiles/serve/f0d567c5-cea6-4a60-923e-e9fb4a4019e8/", "../data/klein_2015.h5ad")
}
if(! file.exists("../data/svensson_2017_1.h5ad")){
download.file("https://data.caltech.edu/tindfiles/serve/3f89d3a5-6ceb-486e-95d4-9bd3f511a706/", "../data/svensson_2017_1.h5ad")
}
if(! file.exists("../data/svensson_2017_2.h5ad")){
download.file("https://data.caltech.edu/tindfiles/serve/16dab9ea-4447-4e23-9aad-e68d052fd789/", "../data/svensson_2017_2.h5ad")
}
if(! file.exists("../data/nih3t3.h5ad")){
download.file("https://data.caltech.edu/tindfiles/serve/a448e98e-89cd-47b3-a134-803bbde29781/", "../data/nih3t3.h5ad")
}
if(! file.exists("../data/hek293t.h5ad")){
download.file("https://data.caltech.edu/tindfiles/serve/b2758046-9247-43ab-b8f0-68882b4f39a3/", "../data/hek293t.h5ad")
}
if(! file.exists("../data/nci-h1975.Rds")){
download.file("https://github.com/LuyiTian/sc_mixology/raw/master/data/csv/sc_10x.metadata.csv.gz", "../data/nci-h1975-metadata.csv.gz")
meta <- read.csv("../data/nci-h1975-metadata.csv.gz")
meta$cell_id <- rownames(meta)
download.file("https://github.com/LuyiTian/sc_mixology/raw/master/data/csv/sc_10x.count.csv.gz", "../data/nci-h1975.csv.gz")
count_mat <- as.matrix(read.csv("../data/nci-h1975.csv.gz"))
gene_info <- AnnotationHub::AnnotationHub()[["AH53537"]] %>%
as.data.frame() %>%
group_by(gene_id) %>%
summarize(chromosome = dplyr::first(seqnames),
gene_name = dplyr::first(gene_name),
gene_biotype = dplyr::first(gene_biotype))
row_df <- tibble(gene_id = rownames(count_mat)) %>%
left_join((gene_info), by = "gene_id") %>%
as.data.frame()
saveRDS(SummarizedExperiment(S4Vectors::SimpleList(counts = count_mat), colData = meta, rowData = row_df), "../data/nci-h1975.Rds")
}
if(! file.exists( "../data/GSE126321.Rds")){
download.file("https://www.ncbi.nlm.nih.gov/geo/download/?acc=GSE126321&format=file", "../data/GSE126321_RAW.tar")
dir.create("../data/GSE126321")
untar("../data/GSE126321_RAW.tar", exdir = "../data/GSE126321")
mat <- Matrix::readMM("../data/GSE126321/GSM3596320_GM18502_matrix.mtx.gz")
genes <- read_tsv("../data/GSE126321/GSM3596320_GM18502_genes.tsv.gz", col_names = c("gene_id", "gene_name"))
barcodes <- read_tsv("../data/GSE126321/GSM3596320_GM18502_barcodes.tsv.gz", col_names = "barcode") %>%
mutate(barcode = str_remove(barcode, "-1"))
qc <- read.delim("../data/GSE126321/GSM3596320_GM18502_cellQC.tsv.gz", sep = "\t") %>%
rownames_to_column("barcode") %>%
as_tibble()
col_df <- left_join(barcodes, qc, by = "barcode") %>%
as.data.frame()
gene_info <- AnnotationHub::AnnotationHub()[["AH53537"]] %>%
as.data.frame() %>%
group_by(gene_id) %>%
summarize(chromosome = dplyr::first(seqnames),
gene_name = dplyr::first(gene_name),
gene_biotype = dplyr::first(gene_biotype))
row_df <- genes %>%
left_join((gene_info), by = "gene_id") %>%
transmute(gene_id, gene_name = gene_name.x, chromosome, gene_biotype) %>%
as.data.frame()
count_mat <- as(mat, "dgCMatrix")
rownames(count_mat) <- row_df$gene_id
colnames(count_mat) <- col_df$barcode
saveRDS(SummarizedExperiment(S4Vectors::SimpleList(counts = count_mat), colData = col_df, rowData = row_df), "../data/GSE126321.Rds")
}
Technical control experiments
se <- zellkonverter::readH5AD("../data/klein_2015.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)

se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 25213 424
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, ercc_gene = str_starts(rownames(se_red), "ERCC-")) %>%
mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
ggplot(aes(x = mu, y = var)) +
geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
geom_line(data = gampoi_pred %>% filter((factor == 100 & var < 1.5e3) | (factor != 100 & var < 4e3)),
aes(group = factor), color = "#DEB554", size = 0.8) +
geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
coord_fixed(expand = FALSE, clip = "off") +
ggrastr::geom_point_rast(aes(color = ercc_gene), size = 0.1, show.legend = FALSE) +
annotate(shadowtext:::GeomShadowText, x = 5e3, y = 5e3, label = expression(Var==mu),
hjust = 0, vjust = 0.5, angle = 45, size = 4, color = "black", bg.colour = "white") +
annotate(shadowtext:::GeomShadowText, x = sqrt(4e3), y = 4e3, label = expression(Var==mu+1*mu^2),
hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
annotate(shadowtext:::GeomShadowText, x = sqrt(5e3 / 0.01), y = 5e3, label = expression(Var==mu+0.01*mu^2),
hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
annotate(shadowtext:::GeomShadowText, x = sqrt(2e3 / 100), y = 2e3, label = expression(Var==mu+100*mu^2),
hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Mean~(mu))) +
scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Variance)) +
scale_color_manual(values = c("TRUE" = "#6c58d1", "FALSE" = "black")) +
ggtitle("Klein 2015", subtitle = "<span style = 'color: #6c58d1'>ERCC spike-ins</span>") +
theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 300 row(s) containing missing values (geom_path).
Warning: Removed 100 row(s) containing missing values (geom_path).
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'

tech_p1 <- last_plot()
se <- zellkonverter::readH5AD("../data/svensson_2017_1.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)

se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 17906 894
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, ercc_gene = str_starts(rownames(se_red), "ERCC-")) %>%
mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
ggplot(aes(x = mu, y = var)) +
geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
# geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
# geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
coord_fixed(expand = FALSE, clip = "off") +
ggrastr::geom_point_rast(aes(color = ercc_gene), size = 0.1, show.legend = FALSE) +
annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Mean~(mu))) +
scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Variance)) +
scale_color_manual(values = c("TRUE" = "#6c58d1", "FALSE" = "black")) +
ggtitle("Svensson 2017 (1)", subtitle = "") +
theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).

tech_p2 <- last_plot()
se <- zellkonverter::readH5AD("../data/svensson_2017_2.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)

se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 18812 803
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, ercc_gene = str_starts(rownames(se_red), "ERCC-")) %>%
mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
ggplot(aes(x = mu, y = var)) +
geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
# geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
# geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
coord_fixed(expand = FALSE, clip = "off") +
ggrastr::geom_point_rast(aes(color = ercc_gene), size = 0.1, show.legend = FALSE) +
annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Mean~(mu))) +
scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Variance)) +
scale_color_manual(values = c("TRUE" = "#6c58d1", "FALSE" = "black")) +
ggtitle("Svensson 2017 (2)", subtitle = "") +
theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).

tech_p3 <- last_plot()
Biological control
se <- zellkonverter::readH5AD("../data/nih3t3.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)

se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 19406 788
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, cell_cycle_gene = rownames(se_red) %in% paste0("mm10_", mouse_cell_cycle_genes)) %>%
mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
ggplot(aes(x = mu, y = var)) +
geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
geom_line(data = gampoi_pred %>% filter((factor == 100 & var < 1.5e3) | (factor != 100 & var < 4e3)),
aes(group = factor), color = "#DEB554", size = 0.8) +
geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
# geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
# geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
coord_fixed(expand = FALSE, clip = "off") +
# geom_point(size = 0.3, alpha = 0.3) +
ggrastr::geom_point_rast(aes(color = cell_cycle_gene), size = 0.1, show.legend = FALSE) +
annotate(shadowtext:::GeomShadowText, x = 5e3, y = 5e3, label = expression(Var==mu),
hjust = 0, vjust = 0.5, angle = 45, size = 4, color = "black", bg.colour = "white") +
annotate(shadowtext:::GeomShadowText, x = sqrt(4e3), y = 4e3, label = expression(Var==mu+1*mu^2),
hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
annotate(shadowtext:::GeomShadowText, x = sqrt(5e3 / 0.01), y = 5e3, label = expression(Var==mu+0.01*mu^2),
hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
annotate(shadowtext:::GeomShadowText, x = sqrt(2e3 / 100), y = 2e3, label = expression(Var==mu+100*mu^2),
hjust = 0, vjust = 0.4, angle = atan(2) / pi * 180, size = 4, color = "black", bg.colour = "white") +
annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Mean~(mu))) +
scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Variance)) +
scale_color_manual(values = c("TRUE" = "#87172f", "FALSE" = "black")) +
ggtitle("NIH/3T3 Cells", subtitle = "<span style = 'color: #87172f'>Cell cycle marker</span> genes.") +
theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 300 row(s) containing missing values (geom_path).
Warning: Removed 100 row(s) containing missing values (geom_path).
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'

p1 <- last_plot()
se <- zellkonverter::readH5AD("../data/hek293t.h5ad")
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)

se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 22804 565
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, cell_cycle_gene = rownames(se_red) %in% paste0("hg19_", human_cell_cycle_genes)) %>%
mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
ggplot(aes(x = mu, y = var)) +
geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
# geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
# geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
coord_fixed(expand = FALSE, clip = "off") +
ggrastr::geom_point_rast(aes(color = cell_cycle_gene), size = 0.1, show.legend = FALSE) +
annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Mean~(mu))) +
scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Variance)) +
scale_color_manual(values = c("TRUE" = "#87172f", "FALSE" = "black")) +
ggtitle("HEK 293T Cells", subtitle = "") +
theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).

p2 <- last_plot()
se_full <- readRDS("../data/nci-h1975.Rds")
table(se_full$cell_line)
H1975 H2228 HCC827
313 315 274
se <- se_full[, se_full$cell_line == "H1975"]
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)

se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 15932 99
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, cell_cycle_gene = rownames(se_red) %in% human_cell_cycle_genes) %>%
mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
ggplot(aes(x = mu, y = var)) +
geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
# geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
# geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
coord_fixed(expand = FALSE, clip = "off") +
ggrastr::geom_point_rast(aes(color = cell_cycle_gene), size = 0.1, show.legend = FALSE) +
annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Mean~(mu))) +
scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Variance)) +
scale_color_manual(values = c("TRUE" = "#87172f", "FALSE" = "black")) +
ggtitle("NCI-H1975 Cells", subtitle = "") +
theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).

p3 <- last_plot()
se <- readRDS("../data/GSE126321.Rds")
# table(se$cellPhase)
# se <- se[, se$cellPhase == "S"]
sf <- colSums2(assay(se))
thres <- quantile(sf, 0.5) * c(1, 1.3)
hist(sf, breaks = 50); abline(v = thres, col = "red", lwd = 2)

se_red <- se[, sf > thres[1] & sf < thres[2]]
sf_red <- sf[sf > thres[1] & sf < thres[2]]
se_red <- se_red[rowSums2(assay(se_red)) > 0]
dim(se_red)
[1] 17909 1242
mu <- rowMeans2(assay(se_red))
var <- rowVars(assay(se_red))
tibble(mu, var, cell_cycle_gene = rownames(se_red) %in% human_cell_cycle_genes) %>%
mutate(mu_pred = mu, mu_sq_pred = mu^2) %>%
ggplot(aes(x = mu, y = var)) +
geom_line(data = poisson_pred, aes(group = factor), color = "lightgray", size = 0.1) +
# geom_line(data = gampoi_pred %>% filter(var < 4e3), aes(group = factor), color = "#DEB554", size = 0.8) +
# geom_line(data = poisson_pred %>% filter(factor == 1 & mu < 4e3), aes(group = factor), color = "#C981DE", size = 1.2) +
geom_line(data = gampoi_pred, aes(group = factor), color = "#DEB554", size = 0.8) +
geom_line(data = poisson_pred %>% filter(factor == 1), aes(group = factor), color = "#C981DE", size = 1.2) +
coord_fixed(expand = FALSE, clip = "off") +
ggrastr::geom_point_rast(aes(color = cell_cycle_gene), size = 0.1, show.legend = FALSE) +
annotation_logticks(scaled = TRUE, outside = FALSE, size = 0.2,
short = unit(0.05, "cm"), mid = unit(0.1, "cm"), long = unit(0.15, "cm")) +
scale_x_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e5),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Mean~(mu))) +
scale_y_log10(breaks = c(0.001, 0.1, 10, 1000, 1e5), limits = c(1e-3, 1e6),
labels = c(expression(10^-3), expression(10^-1),
expression(10), expression(10^3), expression(10^5)),
name = expression(Variance)) +
scale_color_manual(values = c("TRUE" = "#87172f", "FALSE" = "black")) +
ggtitle("GM18502 Cells", subtitle = "") +
theme(plot.subtitle = ggtext::element_markdown())
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 1812 rows containing missing values (geom_point).

p4 <- last_plot()
p_tech <- cowplot::plot_grid(tech_p1, tech_p2, tech_p3, NULL, nrow = 1, align = "h")
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 300 row(s) containing missing values (geom_path).
Warning: Removed 100 row(s) containing missing values (geom_path).
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
p_bio <- cowplot::plot_grid(p1, p2, p3, p4, nrow = 1, align = "h")
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 300 row(s) containing missing values (geom_path).
Warning: Removed 100 row(s) containing missing values (geom_path).
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning in is.na(x) :
is.na() applied to non-(list or vector) of type 'expression'
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 9803 row(s) containing missing values (geom_path).
Warning: Removed 1203 row(s) containing missing values (geom_path).
Warning: Removed 200 row(s) containing missing values (geom_path).
Warning: Removed 1812 rows containing missing values (geom_point).
tech_title <- cowplot::ggdraw() + cowplot::draw_label("(A) Droplets with RNA solution (technical control)",
fontface = "bold", x = 0.02, hjust = 0, size = 18)
bio_title <- cowplot::ggdraw() + cowplot::draw_label("(B) Cell line populations (biological control)",
fontface = "bold", x = 0.02, hjust = 0, size = 18)
p_res <- cowplot::plot_grid(tech_title, p_tech, bio_title, p_bio, ncol = 1,
rel_heights = c(0.2, 1, 0.2, 1))
p_res

cowplot::save_plot("../output/mean_variance_relation_homnogeneous_cells.pdf", p_res, nrow = 2, ncol = 4, base_asp = 0.68, base_height = 5)
Session Info
sessionInfo()
R version 4.1.0 (2021-05-18)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Mojave 10.14.6
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] parallel stats4 stats graphics grDevices utils datasets methods base
other attached packages:
[1] org.Mm.eg.db_3.13.0 org.Hs.eg.db_3.13.0 AnnotationDbi_1.54.1 SingleCellExperiment_1.14.1 SummarizedExperiment_1.22.0 Biobase_2.52.0
[7] GenomicRanges_1.44.0 GenomeInfoDb_1.28.0 IRanges_2.26.0 S4Vectors_0.30.0 BiocGenerics_0.38.0 MatrixGenerics_1.4.0
[13] matrixStats_0.59.0 forcats_0.5.1 stringr_1.4.0 dplyr_1.0.7 purrr_0.3.4 readr_1.4.0
[19] tidyr_1.1.3 tibble_3.1.2 ggplot2_3.3.4 tidyverse_1.3.1
loaded via a namespace (and not attached):
[1] ggbeeswarm_0.6.0 colorspace_2.0-1 ellipsis_0.3.2 markdown_1.1 XVector_0.32.0 fs_1.5.0
[7] gridtext_0.1.4 ggtext_0.1.1 rstudioapi_0.13 farver_2.1.0 bit64_4.0.5 interactiveDisplayBase_1.30.0
[13] fansi_0.5.0 lubridate_1.7.10 xml2_1.3.2 sparseMatrixStats_1.4.0 cachem_1.0.5 knitr_1.33
[19] jsonlite_1.7.2 Cairo_1.5-12.2 broom_0.7.7 dbplyr_2.1.1 png_0.1-7 shiny_1.6.0
[25] BiocManager_1.30.16 compiler_4.1.0 httr_1.4.2 basilisk_1.4.0 backports_1.2.1 assertthat_0.2.1
[31] Matrix_1.3-4 fastmap_1.1.0 cli_2.5.0 later_1.2.0 htmltools_0.5.1.1 tools_4.1.0
[37] gtable_0.3.0 glue_1.4.2 GenomeInfoDbData_1.2.6 rappdirs_0.3.3 Rcpp_1.0.6 cellranger_1.1.0
[43] vctrs_0.3.8 Biostrings_2.60.1 zellkonverter_1.2.0 xfun_0.24 rvest_1.0.0 mime_0.10
[49] lifecycle_1.0.0 AnnotationHub_3.0.0 zlibbioc_1.38.0 scales_1.1.1 basilisk.utils_1.4.0 ragg_1.1.3
[55] hms_1.1.0 promises_1.2.0.1 yaml_2.2.1 curl_4.3.1 memoise_2.0.0 reticulate_1.20
[61] ggrastr_0.2.3 stringi_1.6.2 RSQLite_2.2.7 BiocVersion_3.13.1 filelock_1.0.2 systemfonts_1.0.2
[67] rlang_0.4.11 pkgconfig_2.0.3 bitops_1.0-7 lattice_0.20-44 shadowtext_0.0.8 cowplot_1.1.1
[73] bit_4.0.4 tidyselect_1.1.1 magrittr_2.0.1 R6_2.5.0 generics_0.1.0 DelayedArray_0.18.0
[79] DBI_1.1.1 pillar_1.6.1 haven_2.4.1 withr_2.4.2 KEGGREST_1.32.0 RCurl_1.98-1.3
[85] dir.expiry_1.0.0 modelr_0.1.8 crayon_1.4.1 utf8_1.2.1 BiocFileCache_2.0.0 grid_4.1.0
[91] readxl_1.3.1 blob_1.2.1 reprex_2.0.0 digest_0.6.27 xtable_1.8-4 httpuv_1.6.1
[97] textshaping_0.3.5 munsell_0.5.0 beeswarm_0.4.0 vipor_0.4.5
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShNYXRyaXhHZW5lcmljcykKbGlicmFyeShTaW5nbGVDZWxsRXhwZXJpbWVudCkKYGBgCgpgYGB7cn0KbHNlcSA8LSBmdW5jdGlvbihmcm9tLCB0bywgbGVuZ3RoLm91dCl7CiAgZXhwKHNlcShsb2coZnJvbSksIGxvZyh0byksIGxlbmd0aC5vdXQgPSBsZW5ndGgub3V0KSkKfQp0aGVtZV9zZXQoY293cGxvdDo6dGhlbWVfY293cGxvdCgpKQpgYGAKCgoKYGBge3J9CmxpYnJhcnkob3JnLkhzLmVnLmRiKQpodW1hbl9jZWxsX2N5Y2xlX2dlbmVzIDwtIHNlbGVjdChvcmcuSHMuZWcuZGIsIGtleXR5cGUgPSAiR09BTEwiLCBrZXlzID0gIkdPOjAwMDcwNDkiLCBjb2x1bW5zID0gIkVOU0VNQkwiKVssICJFTlNFTUJMIl0KbGlicmFyeShvcmcuTW0uZWcuZGIpCm1vdXNlX2NlbGxfY3ljbGVfZ2VuZXMgPC0gc2VsZWN0KG9yZy5NbS5lZy5kYiwga2V5dHlwZSA9ICJHT0FMTCIsIGtleXMgPSAiR086MDAwNzA0OSIsIGNvbHVtbnMgPSAiRU5TRU1CTCIpWywgIkVOU0VNQkwiXQpgYGAKCgpgYGB7cn0KbXVfc3VwIDwtIGxzZXEoMWUtNCwgMWU2LCBsZW5ndGgub3V0ID0gMTAwMSkKcG9pc3Nvbl9wcmVkIDwtIGNyb3NzX2RmKGxpc3QobXUgPSBtdV9zdXAsIGZhY3RvciA9IDEwXnNlcSgtOCwgOCkpKSAlPiUKICBtdXRhdGUodmFyID0gbXUgKiBmYWN0b3IpCgpnYW1wb2lfcHJlZCA8LSBjcm9zc19kZihsaXN0KG11ID0gbXVfc3VwLCBmYWN0b3IgPSAxMF5zZXEoLTIsIDIsIGJ5ID0gMikpKSAlPiUKICBtdXRhdGUodmFyID0gbXUgKyBtdV4yICogZmFjdG9yKSAKYGBgCgojIFByZXBhcmUgRGF0YQoKCiMjIERvd25sb2FkIGRhdGEKCmBgYHtyfQojIFdvcmsgYXJvdW5kIGZvciBzb21lIGJ1ZyBpbiB6ZWxsa29udmVydGVyCiMgaHR0cHM6Ly9naXRodWIuY29tL3RoZWlzbGFiL3plbGxrb252ZXJ0ZXIvaXNzdWVzLzQ1CnNldEFzKCJkZ1JNYXRyaXgiLCB0byA9ICJkZ0NNYXRyaXgiLCBmdW5jdGlvbihmcm9tKXsKICBhcyhhcyhmcm9tLCAiQ3NwYXJzZU1hdHJpeCIpLCAiZGdDTWF0cml4IikKfSkKYGBgCgoKYGBge3J9CmlmKCEgZmlsZS5leGlzdHMoIi4uL2RhdGEva2xlaW5fMjAxNS5oNWFkIikpewogIGRvd25sb2FkLmZpbGUoImh0dHBzOi8vZGF0YS5jYWx0ZWNoLmVkdS90aW5kZmlsZXMvc2VydmUvZjBkNTY3YzUtY2VhNi00YTYwLTkyM2UtZTlmYjRhNDAxOWU4LyIsICIuLi9kYXRhL2tsZWluXzIwMTUuaDVhZCIpCn0KaWYoISBmaWxlLmV4aXN0cygiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzEuaDVhZCIpKXsKICBkb3dubG9hZC5maWxlKCJodHRwczovL2RhdGEuY2FsdGVjaC5lZHUvdGluZGZpbGVzL3NlcnZlLzNmODlkM2E1LTZjZWItNDg2ZS05NWQ0LTliZDNmNTExYTcwNi8iLCAiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzEuaDVhZCIpCn0KaWYoISBmaWxlLmV4aXN0cygiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzIuaDVhZCIpKXsKICBkb3dubG9hZC5maWxlKCJodHRwczovL2RhdGEuY2FsdGVjaC5lZHUvdGluZGZpbGVzL3NlcnZlLzE2ZGFiOWVhLTQ0NDctNGUyMy05YWFkLWU2OGQwNTJmZDc4OS8iLCAiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzIuaDVhZCIpCn0KaWYoISBmaWxlLmV4aXN0cygiLi4vZGF0YS9uaWgzdDMuaDVhZCIpKXsKICBkb3dubG9hZC5maWxlKCJodHRwczovL2RhdGEuY2FsdGVjaC5lZHUvdGluZGZpbGVzL3NlcnZlL2E0NDhlOThlLTg5Y2QtNDdiMy1hMTM0LTgwM2JiZGUyOTc4MS8iLCAiLi4vZGF0YS9uaWgzdDMuaDVhZCIpCn0KaWYoISBmaWxlLmV4aXN0cygiLi4vZGF0YS9oZWsyOTN0Lmg1YWQiKSl7CiAgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9kYXRhLmNhbHRlY2guZWR1L3RpbmRmaWxlcy9zZXJ2ZS9iMjc1ODA0Ni05MjQ3LTQzYWItYjhmMC02ODg4MmI0ZjM5YTMvIiwgIi4uL2RhdGEvaGVrMjkzdC5oNWFkIikKfQppZighIGZpbGUuZXhpc3RzKCIuLi9kYXRhL25jaS1oMTk3NS5SZHMiKSl7CiAgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9naXRodWIuY29tL0x1eWlUaWFuL3NjX21peG9sb2d5L3Jhdy9tYXN0ZXIvZGF0YS9jc3Yvc2NfMTB4Lm1ldGFkYXRhLmNzdi5neiIsICIuLi9kYXRhL25jaS1oMTk3NS1tZXRhZGF0YS5jc3YuZ3oiKSAKICBtZXRhIDwtIHJlYWQuY3N2KCIuLi9kYXRhL25jaS1oMTk3NS1tZXRhZGF0YS5jc3YuZ3oiKQogIG1ldGEkY2VsbF9pZCA8LSByb3duYW1lcyhtZXRhKQogIAogIGRvd25sb2FkLmZpbGUoImh0dHBzOi8vZ2l0aHViLmNvbS9MdXlpVGlhbi9zY19taXhvbG9neS9yYXcvbWFzdGVyL2RhdGEvY3N2L3NjXzEweC5jb3VudC5jc3YuZ3oiLCAiLi4vZGF0YS9uY2ktaDE5NzUuY3N2Lmd6IikgCiAgY291bnRfbWF0IDwtIGFzLm1hdHJpeChyZWFkLmNzdigiLi4vZGF0YS9uY2ktaDE5NzUuY3N2Lmd6IikpCiAgZ2VuZV9pbmZvIDwtIEFubm90YXRpb25IdWI6OkFubm90YXRpb25IdWIoKVtbIkFINTM1MzciXV0gJT4lCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgICBncm91cF9ieShnZW5lX2lkKSAlPiUKICAgIHN1bW1hcml6ZShjaHJvbW9zb21lID0gZHBseXI6OmZpcnN0KHNlcW5hbWVzKSwKICAgICAgICAgICAgICBnZW5lX25hbWUgPSBkcGx5cjo6Zmlyc3QoZ2VuZV9uYW1lKSwKICAgICAgICAgICAgICBnZW5lX2Jpb3R5cGUgPSBkcGx5cjo6Zmlyc3QoZ2VuZV9iaW90eXBlKSkKICByb3dfZGYgPC0gdGliYmxlKGdlbmVfaWQgPSByb3duYW1lcyhjb3VudF9tYXQpKSAlPiUKICAgIGxlZnRfam9pbigoZ2VuZV9pbmZvKSwgYnkgPSAiZ2VuZV9pZCIpICU+JQogICAgYXMuZGF0YS5mcmFtZSgpCiAgc2F2ZVJEUyhTdW1tYXJpemVkRXhwZXJpbWVudChTNFZlY3RvcnM6OlNpbXBsZUxpc3QoY291bnRzID0gY291bnRfbWF0KSwgY29sRGF0YSA9IG1ldGEsIHJvd0RhdGEgPSByb3dfZGYpLCAiLi4vZGF0YS9uY2ktaDE5NzUuUmRzIikKfQppZighIGZpbGUuZXhpc3RzKCAiLi4vZGF0YS9HU0UxMjYzMjEuUmRzIikpewogIGRvd25sb2FkLmZpbGUoImh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvZ2VvL2Rvd25sb2FkLz9hY2M9R1NFMTI2MzIxJmZvcm1hdD1maWxlIiwgIi4uL2RhdGEvR1NFMTI2MzIxX1JBVy50YXIiKQogIGRpci5jcmVhdGUoIi4uL2RhdGEvR1NFMTI2MzIxIikKICB1bnRhcigiLi4vZGF0YS9HU0UxMjYzMjFfUkFXLnRhciIsIGV4ZGlyID0gIi4uL2RhdGEvR1NFMTI2MzIxIikKICBtYXQgPC0gTWF0cml4OjpyZWFkTU0oIi4uL2RhdGEvR1NFMTI2MzIxL0dTTTM1OTYzMjBfR00xODUwMl9tYXRyaXgubXR4Lmd6IikKICBnZW5lcyA8LSByZWFkX3RzdigiLi4vZGF0YS9HU0UxMjYzMjEvR1NNMzU5NjMyMF9HTTE4NTAyX2dlbmVzLnRzdi5neiIsIGNvbF9uYW1lcyA9IGMoImdlbmVfaWQiLCAiZ2VuZV9uYW1lIikpCiAgYmFyY29kZXMgPC0gcmVhZF90c3YoIi4uL2RhdGEvR1NFMTI2MzIxL0dTTTM1OTYzMjBfR00xODUwMl9iYXJjb2Rlcy50c3YuZ3oiLCBjb2xfbmFtZXMgPSAiYmFyY29kZSIpICU+JQogICAgbXV0YXRlKGJhcmNvZGUgPSBzdHJfcmVtb3ZlKGJhcmNvZGUsICItMSIpKQogIHFjIDwtIHJlYWQuZGVsaW0oIi4uL2RhdGEvR1NFMTI2MzIxL0dTTTM1OTYzMjBfR00xODUwMl9jZWxsUUMudHN2Lmd6Iiwgc2VwID0gIlx0IikgJT4lCiAgICByb3duYW1lc190b19jb2x1bW4oImJhcmNvZGUiKSAgJT4lCiAgICBhc190aWJibGUoKQogIGNvbF9kZiA8LSBsZWZ0X2pvaW4oYmFyY29kZXMsIHFjLCBieSA9ICJiYXJjb2RlIikgJT4lCiAgICBhcy5kYXRhLmZyYW1lKCkKICBnZW5lX2luZm8gPC0gQW5ub3RhdGlvbkh1Yjo6QW5ub3RhdGlvbkh1YigpW1siQUg1MzUzNyJdXSAlPiUKICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUKICAgIGdyb3VwX2J5KGdlbmVfaWQpICU+JQogICAgc3VtbWFyaXplKGNocm9tb3NvbWUgPSBkcGx5cjo6Zmlyc3Qoc2VxbmFtZXMpLAogICAgICAgICAgICAgIGdlbmVfbmFtZSA9IGRwbHlyOjpmaXJzdChnZW5lX25hbWUpLAogICAgICAgICAgICAgIGdlbmVfYmlvdHlwZSA9IGRwbHlyOjpmaXJzdChnZW5lX2Jpb3R5cGUpKQogIHJvd19kZiA8LSBnZW5lcyAlPiUKICAgIGxlZnRfam9pbigoZ2VuZV9pbmZvKSwgYnkgPSAiZ2VuZV9pZCIpICU+JQogICAgdHJhbnNtdXRlKGdlbmVfaWQsIGdlbmVfbmFtZSA9IGdlbmVfbmFtZS54LCBjaHJvbW9zb21lLCBnZW5lX2Jpb3R5cGUpICU+JQogICAgYXMuZGF0YS5mcmFtZSgpCiAgY291bnRfbWF0IDwtIGFzKG1hdCwgImRnQ01hdHJpeCIpCiAgcm93bmFtZXMoY291bnRfbWF0KSA8LSByb3dfZGYkZ2VuZV9pZAogIGNvbG5hbWVzKGNvdW50X21hdCkgPC0gY29sX2RmJGJhcmNvZGUKICBzYXZlUkRTKFN1bW1hcml6ZWRFeHBlcmltZW50KFM0VmVjdG9yczo6U2ltcGxlTGlzdChjb3VudHMgPSBjb3VudF9tYXQpLCBjb2xEYXRhID0gY29sX2RmLCByb3dEYXRhID0gcm93X2RmKSwgIi4uL2RhdGEvR1NFMTI2MzIxLlJkcyIpCn0KCmBgYAoKCiMgVGVjaG5pY2FsIGNvbnRyb2wgZXhwZXJpbWVudHMKCmBgYHtyfQpzZSA8LSB6ZWxsa29udmVydGVyOjpyZWFkSDVBRCgiLi4vZGF0YS9rbGVpbl8yMDE1Lmg1YWQiKQpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQpgYGAKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGVyY2NfZ2VuZSA9IHN0cl9zdGFydHMocm93bmFtZXMoc2VfcmVkKSwgIkVSQ0MtIikpICU+JQogIG11dGF0ZShtdV9wcmVkID0gbXUsIG11X3NxX3ByZWQgPSBtdV4yKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtdSwgeSA9IHZhcikpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICJsaWdodGdyYXkiLCBzaXplID0gMC4xKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IGdhbXBvaV9wcmVkICU+JSBmaWx0ZXIoKGZhY3RvciA9PSAxMDAgJiB2YXIgPCAxLjVlMykgfCAoZmFjdG9yICE9IDEwMCAmIHZhciA8IDRlMykpLCAKICAgICAgICAgICAgICBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjREVCNTU0Iiwgc2l6ZSA9IDAuOCkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQgJT4lIGZpbHRlcihmYWN0b3IgPT0gMSAmIG11IDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGNvb3JkX2ZpeGVkKGV4cGFuZCA9IEZBTFNFLCBjbGlwID0gIm9mZiIpICsKICAgIGdncmFzdHI6Omdlb21fcG9pbnRfcmFzdChhZXMoY29sb3IgPSBlcmNjX2dlbmUpLCBzaXplID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBhbm5vdGF0ZShzaGFkb3d0ZXh0Ojo6R2VvbVNoYWRvd1RleHQsIHggPSA1ZTMsIHkgPSA1ZTMsIGxhYmVsID0gZXhwcmVzc2lvbihWYXI9PW11KSwKICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUsIGFuZ2xlID0gNDUsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIsIGJnLmNvbG91ciA9ICJ3aGl0ZSIpICsKICAgIGFubm90YXRlKHNoYWRvd3RleHQ6OjpHZW9tU2hhZG93VGV4dCwgeCA9IHNxcnQoNGUzKSwgeSA9IDRlMywgbGFiZWwgPSBleHByZXNzaW9uKFZhcj09bXUrMSptdV4yKSwKICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjQsIGFuZ2xlID0gYXRhbigyKSAvIHBpICogMTgwLCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siLCBiZy5jb2xvdXIgPSAid2hpdGUiKSArCiAgICBhbm5vdGF0ZShzaGFkb3d0ZXh0Ojo6R2VvbVNoYWRvd1RleHQsIHggPSBzcXJ0KDVlMyAvIDAuMDEpLCB5ID0gNWUzLCBsYWJlbCA9IGV4cHJlc3Npb24oVmFyPT1tdSswLjAxKm11XjIpLAogICAgICAgICAgICAgaGp1c3QgPSAwLCB2anVzdCA9IDAuNCwgYW5nbGUgPSBhdGFuKDIpIC8gcGkgKiAxODAsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIsIGJnLmNvbG91ciA9ICJ3aGl0ZSIpICsKICAgIGFubm90YXRlKHNoYWRvd3RleHQ6OjpHZW9tU2hhZG93VGV4dCwgeCA9IHNxcnQoMmUzIC8gMTAwKSwgeSA9IDJlMywgbGFiZWwgPSBleHByZXNzaW9uKFZhcj09bXUrMTAwKm11XjIpLAogICAgICAgICAgICAgaGp1c3QgPSAwLCB2anVzdCA9IDAuNCwgYW5nbGUgPSBhdGFuKDIpIC8gcGkgKiAxODAsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIsIGJnLmNvbG91ciA9ICJ3aGl0ZSIpICsKICAgIGFubm90YXRpb25fbG9ndGlja3Moc2NhbGVkID0gVFJVRSwgb3V0c2lkZSA9IEZBTFNFLCBzaXplID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICBzaG9ydCA9IHVuaXQoMC4wNSwgImNtIiksIG1pZCA9IHVuaXQoMC4xLCAiY20iKSwgbG9uZyA9IHVuaXQoMC4xNSwgImNtIikpICsKICAgIHNjYWxlX3hfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTUpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oTWVhbn4obXUpKSkgKwogICAgc2NhbGVfeV9sb2cxMChicmVha3MgPSBjKDAuMDAxLCAwLjEsIDEwLCAxMDAwLCAxZTUpLCBsaW1pdHMgPSBjKDFlLTMsIDFlNiksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZXhwcmVzc2lvbigxMF4tMyksIGV4cHJlc3Npb24oMTBeLTEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uKDEwKSwgIGV4cHJlc3Npb24oMTBeMyksIGV4cHJlc3Npb24oMTBeNSkpLAogICAgICAgICAgICAgICAgICBuYW1lID0gZXhwcmVzc2lvbihWYXJpYW5jZSkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICIjNmM1OGQxIiwgIkZBTFNFIiA9ICJibGFjayIpKSArCiAgICBnZ3RpdGxlKCJLbGVpbiAyMDE1Iiwgc3VidGl0bGUgPSAiPHNwYW4gc3R5bGUgPSAnY29sb3I6ICM2YzU4ZDEnPkVSQ0Mgc3Bpa2UtaW5zPC9zcGFuPiIpICsKICAgIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSkKCgp0ZWNoX3AxIDwtIGxhc3RfcGxvdCgpCmBgYAoKCmBgYHtyfQpzZSA8LSB6ZWxsa29udmVydGVyOjpyZWFkSDVBRCgiLi4vZGF0YS9zdmVuc3Nvbl8yMDE3XzEuaDVhZCIpCnNmIDwtIGNvbFN1bXMyKGFzc2F5KHNlKSkKdGhyZXMgPC0gcXVhbnRpbGUoc2YsIDAuNSkgKiBjKDEsIDEuMykKaGlzdChzZiwgYnJlYWtzID0gNTApOyBhYmxpbmUodiA9IHRocmVzLCBjb2wgPSAicmVkIiwgbHdkID0gMikKCnNlX3JlZCA8LSBzZVssIHNmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZl9yZWQgPC0gc2Zbc2YgPiB0aHJlc1sxXSAmIHNmIDwgdGhyZXNbMl1dCnNlX3JlZCA8LSBzZV9yZWRbcm93U3VtczIoYXNzYXkoc2VfcmVkKSkgPiAwXQpkaW0oc2VfcmVkKQoKbXUgPC0gcm93TWVhbnMyKGFzc2F5KHNlX3JlZCkpCnZhciA8LSByb3dWYXJzKGFzc2F5KHNlX3JlZCkpCmBgYAoKCmBgYHtyfQp0aWJibGUobXUsIHZhciwgZXJjY19nZW5lID0gc3RyX3N0YXJ0cyhyb3duYW1lcyhzZV9yZWQpLCAiRVJDQy0iKSkgJT4lCiAgbXV0YXRlKG11X3ByZWQgPSBtdSwgbXVfc3FfcHJlZCA9IG11XjIpICU+JQogIGdncGxvdChhZXMoeCA9IG11LCB5ID0gdmFyKSkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQsIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gImxpZ2h0Z3JheSIsIHNpemUgPSAwLjEpICsKICAgICMgZ2VvbV9saW5lKGRhdGEgPSBnYW1wb2lfcHJlZCAlPiUgZmlsdGVyKHZhciA8IDRlMyksIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNERUI1NTQiLCBzaXplID0gMC44KSArCiAgICAjIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEgJiBtdSA8IDRlMyksIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNDOTgxREUiLCBzaXplID0gMS4yKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IGdhbXBvaV9wcmVkLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjREVCNTU0Iiwgc2l6ZSA9IDAuOCkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQgJT4lIGZpbHRlcihmYWN0b3IgPT0gMSksIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNDOTgxREUiLCBzaXplID0gMS4yKSArCiAgICBjb29yZF9maXhlZChleHBhbmQgPSBGQUxTRSwgY2xpcCA9ICJvZmYiKSArCiAgICBnZ3Jhc3RyOjpnZW9tX3BvaW50X3Jhc3QoYWVzKGNvbG9yID0gZXJjY19nZW5lKSwgc2l6ZSA9IDAuMSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgYW5ub3RhdGlvbl9sb2d0aWNrcyhzY2FsZWQgPSBUUlVFLCBvdXRzaWRlID0gRkFMU0UsIHNpemUgPSAwLjIsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3J0ID0gdW5pdCgwLjA1LCAiY20iKSwgbWlkID0gdW5pdCgwLjEsICJjbSIpLCBsb25nID0gdW5pdCgwLjE1LCAiY20iKSkgKwogICAgc2NhbGVfeF9sb2cxMChicmVha3MgPSBjKDAuMDAxLCAwLjEsIDEwLCAxMDAwLCAxZTUpLCBsaW1pdHMgPSBjKDFlLTMsIDFlNSksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZXhwcmVzc2lvbigxMF4tMyksIGV4cHJlc3Npb24oMTBeLTEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uKDEwKSwgIGV4cHJlc3Npb24oMTBeMyksIGV4cHJlc3Npb24oMTBeNSkpLAogICAgICAgICAgICAgICAgICBuYW1lID0gZXhwcmVzc2lvbihNZWFufihtdSkpKSArCiAgICBzY2FsZV95X2xvZzEwKGJyZWFrcyA9IGMoMC4wMDEsIDAuMSwgMTAsIDEwMDAsIDFlNSksIGxpbWl0cyA9IGMoMWUtMywgMWU2KSwKICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhleHByZXNzaW9uKDEwXi0zKSwgZXhwcmVzc2lvbigxMF4tMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb24oMTApLCAgZXhwcmVzc2lvbigxMF4zKSwgZXhwcmVzc2lvbigxMF41KSksCiAgICAgICAgICAgICAgICAgIG5hbWUgPSBleHByZXNzaW9uKFZhcmlhbmNlKSkgKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gIiM2YzU4ZDEiLCAiRkFMU0UiID0gImJsYWNrIikpICsKICAgIGdndGl0bGUoIlN2ZW5zc29uIDIwMTcgKDEpIiwgc3VidGl0bGUgPSAiIikgKwogICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpKQoKdGVjaF9wMiA8LSBsYXN0X3Bsb3QoKQpgYGAKCgpgYGB7cn0Kc2UgPC0gemVsbGtvbnZlcnRlcjo6cmVhZEg1QUQoIi4uL2RhdGEvc3ZlbnNzb25fMjAxN18yLmg1YWQiKQpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQpgYGAKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGVyY2NfZ2VuZSA9IHN0cl9zdGFydHMocm93bmFtZXMoc2VfcmVkKSwgIkVSQ0MtIikpICU+JQogIG11dGF0ZShtdV9wcmVkID0gbXUsIG11X3NxX3ByZWQgPSBtdV4yKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtdSwgeSA9IHZhcikpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICJsaWdodGdyYXkiLCBzaXplID0gMC4xKSArCiAgICAjIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQgJT4lIGZpbHRlcih2YXIgPCA0ZTMpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjREVCNTU0Iiwgc2l6ZSA9IDAuOCkgKwogICAgIyBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCAlPiUgZmlsdGVyKGZhY3RvciA9PSAxICYgbXUgPCA0ZTMpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBnYW1wb2lfcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgY29vcmRfZml4ZWQoZXhwYW5kID0gRkFMU0UsIGNsaXAgPSAib2ZmIikgKwogICAgZ2dyYXN0cjo6Z2VvbV9wb2ludF9yYXN0KGFlcyhjb2xvciA9IGVyY2NfZ2VuZSksIHNpemUgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGFubm90YXRpb25fbG9ndGlja3Moc2NhbGVkID0gVFJVRSwgb3V0c2lkZSA9IEZBTFNFLCBzaXplID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICBzaG9ydCA9IHVuaXQoMC4wNSwgImNtIiksIG1pZCA9IHVuaXQoMC4xLCAiY20iKSwgbG9uZyA9IHVuaXQoMC4xNSwgImNtIikpICsKICAgIHNjYWxlX3hfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTUpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oTWVhbn4obXUpKSkgKwogICAgc2NhbGVfeV9sb2cxMChicmVha3MgPSBjKDAuMDAxLCAwLjEsIDEwLCAxMDAwLCAxZTUpLCBsaW1pdHMgPSBjKDFlLTMsIDFlNiksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZXhwcmVzc2lvbigxMF4tMyksIGV4cHJlc3Npb24oMTBeLTEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uKDEwKSwgIGV4cHJlc3Npb24oMTBeMyksIGV4cHJlc3Npb24oMTBeNSkpLAogICAgICAgICAgICAgICAgICBuYW1lID0gZXhwcmVzc2lvbihWYXJpYW5jZSkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICIjNmM1OGQxIiwgIkZBTFNFIiA9ICJibGFjayIpKSArCiAgICBnZ3RpdGxlKCJTdmVuc3NvbiAyMDE3ICgyKSIsIHN1YnRpdGxlID0gIiIpICsKICAgIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSkKCnRlY2hfcDMgPC0gbGFzdF9wbG90KCkKYGBgCgoKCiMgQmlvbG9naWNhbCBjb250cm9sCgoKYGBge3J9CnNlIDwtIHplbGxrb252ZXJ0ZXI6OnJlYWRINUFEKCIuLi9kYXRhL25paDN0My5oNWFkIikKc2YgPC0gY29sU3VtczIoYXNzYXkoc2UpKQp0aHJlcyA8LSBxdWFudGlsZShzZiwgMC41KSAqIGMoMSwgMS4zKQpoaXN0KHNmLCBicmVha3MgPSA1MCk7IGFibGluZSh2ID0gdGhyZXMsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQoKc2VfcmVkIDwtIHNlWywgc2YgPiB0aHJlc1sxXSAmIHNmIDwgdGhyZXNbMl1dCnNmX3JlZCA8LSBzZltzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2VfcmVkIDwtIHNlX3JlZFtyb3dTdW1zMihhc3NheShzZV9yZWQpKSA+IDBdCmRpbShzZV9yZWQpCgptdSA8LSByb3dNZWFuczIoYXNzYXkoc2VfcmVkKSkKdmFyIDwtIHJvd1ZhcnMoYXNzYXkoc2VfcmVkKSkKYGBgCgoKYGBge3J9CnRpYmJsZShtdSwgdmFyLCBjZWxsX2N5Y2xlX2dlbmUgPSByb3duYW1lcyhzZV9yZWQpICVpbiUgcGFzdGUwKCJtbTEwXyIsIG1vdXNlX2NlbGxfY3ljbGVfZ2VuZXMpKSAlPiUKICBtdXRhdGUobXVfcHJlZCA9IG11LCBtdV9zcV9wcmVkID0gbXVeMikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbXUsIHkgPSB2YXIpKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAibGlnaHRncmF5Iiwgc2l6ZSA9IDAuMSkgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBnYW1wb2lfcHJlZCAlPiUgZmlsdGVyKChmYWN0b3IgPT0gMTAwICYgdmFyIDwgMS41ZTMpIHwgKGZhY3RvciAhPSAxMDAgJiB2YXIgPCA0ZTMpKSwgCiAgICAgICAgICAgICAgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEgJiBtdSA8IDRlMyksIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNDOTgxREUiLCBzaXplID0gMS4yKSArCiAgICAjIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQsIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNERUI1NTQiLCBzaXplID0gMC44KSArCiAgICAjIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgY29vcmRfZml4ZWQoZXhwYW5kID0gRkFMU0UsIGNsaXAgPSAib2ZmIikgKwogICAgIyBnZW9tX3BvaW50KHNpemUgPSAwLjMsIGFscGhhID0gMC4zKSArCiAgICBnZ3Jhc3RyOjpnZW9tX3BvaW50X3Jhc3QoYWVzKGNvbG9yID0gY2VsbF9jeWNsZV9nZW5lKSwgc2l6ZSA9IDAuMSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogICAgYW5ub3RhdGUoc2hhZG93dGV4dDo6Okdlb21TaGFkb3dUZXh0LCB4ID0gNWUzLCB5ID0gNWUzLCBsYWJlbCA9IGV4cHJlc3Npb24oVmFyPT1tdSksCiAgICAgICAgICAgICBoanVzdCA9IDAsIHZqdXN0ID0gMC41LCBhbmdsZSA9IDQ1LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siLCBiZy5jb2xvdXIgPSAid2hpdGUiKSArCiAgICBhbm5vdGF0ZShzaGFkb3d0ZXh0Ojo6R2VvbVNoYWRvd1RleHQsIHggPSBzcXJ0KDRlMyksIHkgPSA0ZTMsIGxhYmVsID0gZXhwcmVzc2lvbihWYXI9PW11KzEqbXVeMiksCiAgICAgICAgICAgICBoanVzdCA9IDAsIHZqdXN0ID0gMC40LCBhbmdsZSA9IGF0YW4oMikgLyBwaSAqIDE4MCwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIiwgYmcuY29sb3VyID0gIndoaXRlIikgKwogICAgYW5ub3RhdGUoc2hhZG93dGV4dDo6Okdlb21TaGFkb3dUZXh0LCB4ID0gc3FydCg1ZTMgLyAwLjAxKSwgeSA9IDVlMywgbGFiZWwgPSBleHByZXNzaW9uKFZhcj09bXUrMC4wMSptdV4yKSwKICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjQsIGFuZ2xlID0gYXRhbigyKSAvIHBpICogMTgwLCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siLCBiZy5jb2xvdXIgPSAid2hpdGUiKSArCiAgICBhbm5vdGF0ZShzaGFkb3d0ZXh0Ojo6R2VvbVNoYWRvd1RleHQsIHggPSBzcXJ0KDJlMyAvIDEwMCksIHkgPSAyZTMsIGxhYmVsID0gZXhwcmVzc2lvbihWYXI9PW11KzEwMCptdV4yKSwKICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjQsIGFuZ2xlID0gYXRhbigyKSAvIHBpICogMTgwLCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siLCBiZy5jb2xvdXIgPSAid2hpdGUiKSArCiAgICBhbm5vdGF0aW9uX2xvZ3RpY2tzKHNjYWxlZCA9IFRSVUUsIG91dHNpZGUgPSBGQUxTRSwgc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvcnQgPSB1bml0KDAuMDUsICJjbSIpLCBtaWQgPSB1bml0KDAuMSwgImNtIiksIGxvbmcgPSB1bml0KDAuMTUsICJjbSIpKSArCiAgICBzY2FsZV94X2xvZzEwKGJyZWFrcyA9IGMoMC4wMDEsIDAuMSwgMTAsIDEwMDAsIDFlNSksIGxpbWl0cyA9IGMoMWUtMywgMWU1KSwKICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhleHByZXNzaW9uKDEwXi0zKSwgZXhwcmVzc2lvbigxMF4tMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb24oMTApLCAgZXhwcmVzc2lvbigxMF4zKSwgZXhwcmVzc2lvbigxMF41KSksCiAgICAgICAgICAgICAgICAgIG5hbWUgPSBleHByZXNzaW9uKE1lYW5+KG11KSkpICsKICAgIHNjYWxlX3lfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTYpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oVmFyaWFuY2UpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAiIzg3MTcyZiIsICJGQUxTRSIgPSAiYmxhY2siKSkgKwogICAgZ2d0aXRsZSgiTklILzNUMyBDZWxscyIsIHN1YnRpdGxlID0gIjxzcGFuIHN0eWxlID0gJ2NvbG9yOiAjODcxNzJmJz5DZWxsIGN5Y2xlIG1hcmtlcjwvc3Bhbj4gZ2VuZXMuIikgKwogICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpKQoKCnAxIDwtIGxhc3RfcGxvdCgpCmBgYAoKCgoKYGBge3J9CnNlIDwtIHplbGxrb252ZXJ0ZXI6OnJlYWRINUFEKCIuLi9kYXRhL2hlazI5M3QuaDVhZCIpCgpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQoKCmBgYAoKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGNlbGxfY3ljbGVfZ2VuZSA9IHJvd25hbWVzKHNlX3JlZCkgJWluJSBwYXN0ZTAoImhnMTlfIiwgaHVtYW5fY2VsbF9jeWNsZV9nZW5lcykpICU+JQogIG11dGF0ZShtdV9wcmVkID0gbXUsIG11X3NxX3ByZWQgPSBtdV4yKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBtdSwgeSA9IHZhcikpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICJsaWdodGdyYXkiLCBzaXplID0gMC4xKSArCiAgICAjIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQgJT4lIGZpbHRlcih2YXIgPCA0ZTMpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjREVCNTU0Iiwgc2l6ZSA9IDAuOCkgKwogICAgIyBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCAlPiUgZmlsdGVyKGZhY3RvciA9PSAxICYgbXUgPCA0ZTMpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgZ2VvbV9saW5lKGRhdGEgPSBnYW1wb2lfcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgIGdlb21fbGluZShkYXRhID0gcG9pc3Nvbl9wcmVkICU+JSBmaWx0ZXIoZmFjdG9yID09IDEpLCBhZXMoZ3JvdXAgPSBmYWN0b3IpLCBjb2xvciA9ICIjQzk4MURFIiwgc2l6ZSA9IDEuMikgKwogICAgY29vcmRfZml4ZWQoZXhwYW5kID0gRkFMU0UsIGNsaXAgPSAib2ZmIikgKwogICAgZ2dyYXN0cjo6Z2VvbV9wb2ludF9yYXN0KGFlcyhjb2xvciA9IGNlbGxfY3ljbGVfZ2VuZSksIHNpemUgPSAwLjEsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICAgIGFubm90YXRpb25fbG9ndGlja3Moc2NhbGVkID0gVFJVRSwgb3V0c2lkZSA9IEZBTFNFLCBzaXplID0gMC4yLAogICAgICAgICAgICAgICAgICAgICAgICBzaG9ydCA9IHVuaXQoMC4wNSwgImNtIiksIG1pZCA9IHVuaXQoMC4xLCAiY20iKSwgbG9uZyA9IHVuaXQoMC4xNSwgImNtIikpICsKICAgIHNjYWxlX3hfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTUpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oTWVhbn4obXUpKSkgKwogICAgc2NhbGVfeV9sb2cxMChicmVha3MgPSBjKDAuMDAxLCAwLjEsIDEwLCAxMDAwLCAxZTUpLCBsaW1pdHMgPSBjKDFlLTMsIDFlNiksCiAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoZXhwcmVzc2lvbigxMF4tMyksIGV4cHJlc3Npb24oMTBeLTEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleHByZXNzaW9uKDEwKSwgIGV4cHJlc3Npb24oMTBeMyksIGV4cHJlc3Npb24oMTBeNSkpLAogICAgICAgICAgICAgICAgICBuYW1lID0gZXhwcmVzc2lvbihWYXJpYW5jZSkpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9ICIjODcxNzJmIiwgIkZBTFNFIiA9ICJibGFjayIpKSArCiAgICBnZ3RpdGxlKCJIRUsgMjkzVCBDZWxscyIsIHN1YnRpdGxlID0gIiIpICsKICAgIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSkKCnAyIDwtIGxhc3RfcGxvdCgpCmBgYAoKCgpgYGB7cn0Kc2VfZnVsbCA8LSByZWFkUkRTKCIuLi9kYXRhL25jaS1oMTk3NS5SZHMiKQp0YWJsZShzZV9mdWxsJGNlbGxfbGluZSkKYGBgCgpgYGB7cn0Kc2UgPC0gc2VfZnVsbFssIHNlX2Z1bGwkY2VsbF9saW5lID09ICJIMTk3NSJdCgpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQpgYGAKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGNlbGxfY3ljbGVfZ2VuZSA9IHJvd25hbWVzKHNlX3JlZCkgJWluJSBodW1hbl9jZWxsX2N5Y2xlX2dlbmVzKSAlPiUKICBtdXRhdGUobXVfcHJlZCA9IG11LCBtdV9zcV9wcmVkID0gbXVeMikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbXUsIHkgPSB2YXIpKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAibGlnaHRncmF5Iiwgc2l6ZSA9IDAuMSkgKwogICAgIyBnZW9tX2xpbmUoZGF0YSA9IGdhbXBvaV9wcmVkICU+JSBmaWx0ZXIodmFyIDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgICMgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQgJT4lIGZpbHRlcihmYWN0b3IgPT0gMSAmIG11IDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQsIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNERUI1NTQiLCBzaXplID0gMC44KSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCAlPiUgZmlsdGVyKGZhY3RvciA9PSAxKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGNvb3JkX2ZpeGVkKGV4cGFuZCA9IEZBTFNFLCBjbGlwID0gIm9mZiIpICsKICAgIGdncmFzdHI6Omdlb21fcG9pbnRfcmFzdChhZXMoY29sb3IgPSBjZWxsX2N5Y2xlX2dlbmUpLCBzaXplID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBhbm5vdGF0aW9uX2xvZ3RpY2tzKHNjYWxlZCA9IFRSVUUsIG91dHNpZGUgPSBGQUxTRSwgc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvcnQgPSB1bml0KDAuMDUsICJjbSIpLCBtaWQgPSB1bml0KDAuMSwgImNtIiksIGxvbmcgPSB1bml0KDAuMTUsICJjbSIpKSArCiAgICBzY2FsZV94X2xvZzEwKGJyZWFrcyA9IGMoMC4wMDEsIDAuMSwgMTAsIDEwMDAsIDFlNSksIGxpbWl0cyA9IGMoMWUtMywgMWU1KSwKICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhleHByZXNzaW9uKDEwXi0zKSwgZXhwcmVzc2lvbigxMF4tMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb24oMTApLCAgZXhwcmVzc2lvbigxMF4zKSwgZXhwcmVzc2lvbigxMF41KSksCiAgICAgICAgICAgICAgICAgIG5hbWUgPSBleHByZXNzaW9uKE1lYW5+KG11KSkpICsKICAgIHNjYWxlX3lfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTYpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oVmFyaWFuY2UpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAiIzg3MTcyZiIsICJGQUxTRSIgPSAiYmxhY2siKSkgKwogICAgZ2d0aXRsZSgiTkNJLUgxOTc1IENlbGxzIiwgc3VidGl0bGUgPSAiIikgKwogICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGdndGV4dDo6ZWxlbWVudF9tYXJrZG93bigpKQoKcDMgPC0gbGFzdF9wbG90KCkKYGBgCgoKCmBgYHtyfQpzZSA8LSByZWFkUkRTKCIuLi9kYXRhL0dTRTEyNjMyMS5SZHMiKQojIHRhYmxlKHNlJGNlbGxQaGFzZSkKIyBzZSA8LSBzZVssIHNlJGNlbGxQaGFzZSA9PSAiUyJdCgpzZiA8LSBjb2xTdW1zMihhc3NheShzZSkpCnRocmVzIDwtIHF1YW50aWxlKHNmLCAwLjUpICogYygxLCAxLjMpCmhpc3Qoc2YsIGJyZWFrcyA9IDUwKTsgYWJsaW5lKHYgPSB0aHJlcywgY29sID0gInJlZCIsIGx3ZCA9IDIpCgpzZV9yZWQgPC0gc2VbLCBzZiA+IHRocmVzWzFdICYgc2YgPCB0aHJlc1syXV0Kc2ZfcmVkIDwtIHNmW3NmID4gdGhyZXNbMV0gJiBzZiA8IHRocmVzWzJdXQpzZV9yZWQgPC0gc2VfcmVkW3Jvd1N1bXMyKGFzc2F5KHNlX3JlZCkpID4gMF0KZGltKHNlX3JlZCkKCm11IDwtIHJvd01lYW5zMihhc3NheShzZV9yZWQpKQp2YXIgPC0gcm93VmFycyhhc3NheShzZV9yZWQpKQpgYGAKCgpgYGB7cn0KdGliYmxlKG11LCB2YXIsIGNlbGxfY3ljbGVfZ2VuZSA9IHJvd25hbWVzKHNlX3JlZCkgJWluJSBodW1hbl9jZWxsX2N5Y2xlX2dlbmVzKSAlPiUKICBtdXRhdGUobXVfcHJlZCA9IG11LCBtdV9zcV9wcmVkID0gbXVeMikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbXUsIHkgPSB2YXIpKSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAibGlnaHRncmF5Iiwgc2l6ZSA9IDAuMSkgKwogICAgIyBnZW9tX2xpbmUoZGF0YSA9IGdhbXBvaV9wcmVkICU+JSBmaWx0ZXIodmFyIDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0RFQjU1NCIsIHNpemUgPSAwLjgpICsKICAgICMgZ2VvbV9saW5lKGRhdGEgPSBwb2lzc29uX3ByZWQgJT4lIGZpbHRlcihmYWN0b3IgPT0gMSAmIG11IDwgNGUzKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGdlb21fbGluZShkYXRhID0gZ2FtcG9pX3ByZWQsIGFlcyhncm91cCA9IGZhY3RvciksIGNvbG9yID0gIiNERUI1NTQiLCBzaXplID0gMC44KSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IHBvaXNzb25fcHJlZCAlPiUgZmlsdGVyKGZhY3RvciA9PSAxKSwgYWVzKGdyb3VwID0gZmFjdG9yKSwgY29sb3IgPSAiI0M5ODFERSIsIHNpemUgPSAxLjIpICsKICAgIGNvb3JkX2ZpeGVkKGV4cGFuZCA9IEZBTFNFLCBjbGlwID0gIm9mZiIpICsKICAgIGdncmFzdHI6Omdlb21fcG9pbnRfcmFzdChhZXMoY29sb3IgPSBjZWxsX2N5Y2xlX2dlbmUpLCBzaXplID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgICBhbm5vdGF0aW9uX2xvZ3RpY2tzKHNjYWxlZCA9IFRSVUUsIG91dHNpZGUgPSBGQUxTRSwgc2l6ZSA9IDAuMiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvcnQgPSB1bml0KDAuMDUsICJjbSIpLCBtaWQgPSB1bml0KDAuMSwgImNtIiksIGxvbmcgPSB1bml0KDAuMTUsICJjbSIpKSArCiAgICBzY2FsZV94X2xvZzEwKGJyZWFrcyA9IGMoMC4wMDEsIDAuMSwgMTAsIDEwMDAsIDFlNSksIGxpbWl0cyA9IGMoMWUtMywgMWU1KSwKICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhleHByZXNzaW9uKDEwXi0zKSwgZXhwcmVzc2lvbigxMF4tMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cHJlc3Npb24oMTApLCAgZXhwcmVzc2lvbigxMF4zKSwgZXhwcmVzc2lvbigxMF41KSksCiAgICAgICAgICAgICAgICAgIG5hbWUgPSBleHByZXNzaW9uKE1lYW5+KG11KSkpICsKICAgIHNjYWxlX3lfbG9nMTAoYnJlYWtzID0gYygwLjAwMSwgMC4xLCAxMCwgMTAwMCwgMWU1KSwgbGltaXRzID0gYygxZS0zLCAxZTYpLAogICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKGV4cHJlc3Npb24oMTBeLTMpLCBleHByZXNzaW9uKDEwXi0xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhwcmVzc2lvbigxMCksICBleHByZXNzaW9uKDEwXjMpLCBleHByZXNzaW9uKDEwXjUpKSwKICAgICAgICAgICAgICAgICAgbmFtZSA9IGV4cHJlc3Npb24oVmFyaWFuY2UpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSAiIzg3MTcyZiIsICJGQUxTRSIgPSAiYmxhY2siKSkgKwogICAgZ2d0aXRsZSgiR00xODUwMiBDZWxscyIsIHN1YnRpdGxlID0gIiIpICsKICAgIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBnZ3RleHQ6OmVsZW1lbnRfbWFya2Rvd24oKSkKCnA0IDwtIGxhc3RfcGxvdCgpCmBgYAoKCgoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2ggPSA4fQpwX3RlY2ggPC0gY293cGxvdDo6cGxvdF9ncmlkKHRlY2hfcDEsIHRlY2hfcDIsIHRlY2hfcDMsIE5VTEwsIG5yb3cgPSAxLCBhbGlnbiA9ICJoIikKcF9iaW8gPC0gY293cGxvdDo6cGxvdF9ncmlkKHAxLCBwMiwgcDMsIHA0LCBucm93ID0gMSwgYWxpZ24gPSAiaCIpCgp0ZWNoX3RpdGxlIDwtIGNvd3Bsb3Q6OmdnZHJhdygpICsgY293cGxvdDo6ZHJhd19sYWJlbCgiKEEpIERyb3BsZXRzIHdpdGggUk5BIHNvbHV0aW9uICh0ZWNobmljYWwgY29udHJvbCkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsIHggPSAwLjAyLCBoanVzdCA9IDAsIHNpemUgPSAxOCkKYmlvX3RpdGxlIDwtIGNvd3Bsb3Q6OmdnZHJhdygpICsgY293cGxvdDo6ZHJhd19sYWJlbCgiKEIpIENlbGwgbGluZSBwb3B1bGF0aW9ucyAoYmlvbG9naWNhbCBjb250cm9sKSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiLCB4ID0gMC4wMiwgaGp1c3QgPSAwLCBzaXplID0gMTgpCgpwX3JlcyA8LSBjb3dwbG90OjpwbG90X2dyaWQodGVjaF90aXRsZSwgcF90ZWNoLCBiaW9fdGl0bGUsIHBfYmlvLCBuY29sID0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbF9oZWlnaHRzID0gYygwLjIsIDEsIDAuMiwgMSkpCnBfcmVzCmBgYAoKCmBgYHtyfQpjb3dwbG90OjpzYXZlX3Bsb3QoIi4uL291dHB1dC9tZWFuX3ZhcmlhbmNlX3JlbGF0aW9uX2hvbW5vZ2VuZW91c19jZWxscy5wZGYiLCBwX3JlcywgbnJvdyA9IDIsIG5jb2wgPSA0LCBiYXNlX2FzcCA9IDAuNjgsIGJhc2VfaGVpZ2h0ID0gNSkKYGBgCgoKCgoKCgojIFNlc3Npb24gSW5mbwoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgo=